package eduware.ctrl;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import eduware.dozent.MessageQueue;
import eduware.dozent.MoodState;
import eduware.util.FileHandler;

/***********
 * Class to control the message flow of the lecturer
 * 
 * @author Maik
 * 
 */
public class MessageController {

	public interface MessageContainer {
		public String getMessage(String key);
	}

	public class MoodDependantMessage implements MessageContainer {

		HashMap<String, String[]> messages = new HashMap<String, String[]>();
		Random gen = new Random();

		/********
		 * initializes a new mood dependant message
		 * 
		 * @param moodVeryGood
		 *            String array containing all messages for a very good mood
		 * @param moodGood
		 *            String array containing all messages for a good mood
		 * @param moodAverage
		 *            String array containing all messages for an average mood
		 * @param moodBad
		 *            String array containing all messages for a bad mood
		 * @param moodVeryBad
		 *            String array containing all messages for a very bad mood
		 */
		public MoodDependantMessage(String[] moodVeryGood, String[] moodGood,
				String[] moodAverage, String[] moodBad, String[] moodVeryBad) {
			messages.put("veryGood", moodVeryGood);
			messages.put("good", moodGood);
			messages.put("average", moodAverage);
			messages.put("bad", moodBad);
			messages.put("veryBad", moodVeryBad);
		}

		/***********
		 * function to resolve a random message for a certain mood key
		 * 
		 * @param key
		 *            unambigous identifier of the mood
		 */
		public String getMessage(String key) {
			if (messages.containsKey(key)) {
				// message key is contained in the dataset -> get a random
				// element
				String[] strings = messages.get(key);
				int size = strings.length;
				int elem = gen.nextInt(size);
				return strings[elem];
			} else {
				// message key is unknown - display information
				MessageQueue.getInstance().addMessage(
						"Je ne parle pas francais. ;)");
				throw new IllegalArgumentException(
						"The conditional key does not exist: " + key);
			}
		}

		/**********
		 * function to resolve a random message for a certain mood key and
		 * replacing the contents of of placeholders
		 * <code>%i (i = integer)</code> by provided values
		 * 
		 * @param key
		 *            unambigous identifier of the mood
		 * @param substitutions
		 *            string array containing substitutions
		 * @return random mood dependant message
		 */
		public String getMessage(String key, String[] substitutions) {
			String val = getMessage(key);

			// replacing the internal substitution beginning with the percent
			// sign
			for (int i = 0; i < substitutions.length; i++) {
				val = val.replaceAll("%" + (i + 1), substitutions[i]);
			}

			return val;
		}

		/*********
		 * function to determine the corresponding mood dependant message
		 * 
		 * @return message containing the mood dependant message
		 */
		public String getMessage() {
			float mood = MoodState.MOOD.getIndex();
			String key = "veryBad";
			if (mood < 20)
				key = "veryBad";
			else if (mood < 40)
				key = "bad";
			else if (mood < 60)
				key = "average";
			else if (mood < 80)
				key = "good";
			else if (mood <= 100)
				key = "veryGood";
			return this.getMessage(key);
		}

	}

	private HashMap<String, MessageContainer> messages = new HashMap<String, MessageContainer>();

	public MessageController() {
		/***
		 * Definition of Messages
		 */

		try {
			loadMessages();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

	}

	/***
	 * This function is responsible to load the messages definitions stored in
	 * an external file into the program
	 * 
	 * @throws FileNotFoundException
	 */
	public void loadMessages() throws FileNotFoundException {
		// clean the existing message hash map first
		messages.clear();

		// loading XML document from hard disk
		String path = (Ctrl.DEBUG_MODE) ? "config/messages.xml"
				: Ctrl.BASE_PATH + "messages.xml";
		Document doc = FileHandler.getXMLDocument(path, 500);
		// check whether the document exists on the hard disk
		if (doc == null) {
			try {
				// try to reload the file from the internet
				FileHandler.reloadXMLFile("messages.xml", path, false);
				doc = FileHandler.getXMLDocument(path, 500);
			} catch (FileNotFoundException e) {
				throw new FileNotFoundException(
						"Cound not find file for predefined questions");
			}
		}

		// messages are encpsulated in messagesets
		NodeList set = doc.getDocumentElement().getElementsByTagName(
				"messageset");

		String messageId, messageType;
		messageId = "";

		int i, j, k;
		for (k = 0; k < set.getLength(); k++) {

			// define the array lists for all mood states
			ArrayList<String> listVeryGood = new ArrayList<String>();
			ArrayList<String> listGood = new ArrayList<String>();
			ArrayList<String> listAverage = new ArrayList<String>();
			ArrayList<String> listBad = new ArrayList<String>();
			ArrayList<String> listVeryBad = new ArrayList<String>();

			Element nd = (Element) set.item(k);
			NodeList list = nd.getElementsByTagName("messages");

			// determine the message id
			messageId = nd.getAttribute("id").trim();

			for (i = 0; i < list.getLength(); i++) {

				Element node = (Element) list.item(i);

				// determine the type of message cluster
				messageType = node.getAttribute("type").trim();

				NodeList messageList = node.getElementsByTagName("message");

				for (j = 0; j < messageList.getLength(); j++) {

					String msg_val = messageList.item(j).getTextContent()
							.trim();

					// association of meesage types to the according list
					if (messageType.equals("vg"))
						listVeryGood.add(msg_val);
					else if (messageType.equals("g"))
						listGood.add(msg_val);
					else if (messageType.equals("a"))
						listAverage.add(msg_val);
					else if (messageType.equals("b"))
						listBad.add(msg_val);
					else if (messageType.equals("vb"))
						listVeryBad.add(msg_val);

				}

			}

			// finally create an entry in message hash map
			messages.put(messageId, new MoodDependantMessage(listVeryGood
					.toArray(new String[listVeryGood.size()]), listGood
					.toArray(new String[listGood.size()]), listAverage
					.toArray(new String[listAverage.size()]), listBad
					.toArray(new String[listBad.size()]), listVeryBad
					.toArray(new String[listVeryBad.size()])));

		}

	}

	/**************
	 * function to resolve a messageset for a certain message key
	 * 
	 * @param key
	 *            unique key of the message set
	 * @return message set of the associated key
	 * @throws Exception
	 *             Exceptions if the key can not be found
	 */
	public MessageContainer getMessage(String key) throws Exception {
		if (messages.containsKey(key)) {
			return messages.get(key);
		} else {
			// no association found for the respective key - tell the user in a
			// funny way and throw an exception internally
			MessageQueue.getInstance().addMessage(
					"Je ne parle pas francais. ;)");
			throw new Exception(
					"Internal message store does not contain associations for "
							+ key);
		}
	}
}
